package tio.study.helloworld.common;

import java.nio.ByteBuffer;

import org.tio.core.ChannelContext;
import org.tio.core.GroupContext;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.AioHandler;
import org.tio.core.intf.Packet;

/**
 * 实现接口：这里是编解码的公共实现类
 * 由于在这里是一个简单的例子，所以服务端和客户端共用一个handler类
 * @author Administrator
 *
 */
public abstract class AbsHandler implements AioHandler<Object, HelloPacket, Object>{

	/**
	 * 编码
	 */
	public ByteBuffer encode(HelloPacket packet, GroupContext<Object, HelloPacket, Object> groupContext,ChannelContext<Object, HelloPacket, Object> channelContext) {
		byte[] body = packet.getBody();
		int bodyLen = 0;
		if(body != null){
			bodyLen = body.length;
		}
		//bytebuffer的总长度 = 消息头的长度 + 消息体的长度
		int allLen = HelloPacket.HEADER_LENGTH + bodyLen;
		//创建一个新的bytebuffer
		ByteBuffer buffer = ByteBuffer.allocate(allLen);//分配字节缓冲区的大小
		//设置字节序
		buffer.order(groupContext.getByteOrder());
		
		//写入消息头-----消息头的内容就是消息体的长度
		buffer.putInt(bodyLen);
		
		//写入消息体
		if(body != null){
			buffer.put(body); //put():将给定字节写入当前位置的缓冲区，然后增加位置。
		}
		return buffer;
	}

	/**
	 * 解码
	 */
	public HelloPacket decode(ByteBuffer buffer, ChannelContext<Object, HelloPacket, Object> channelContext) throws AioDecodeException {
		
		/**
		 * limit : 用来表示bytes实际装了多少数据，limit<=capacity
		 * position ：用来表示在哪个位置开始往bytes写数据或读数据
		 */
		int readableLength = buffer.limit() - buffer.position();//可读数据长度
		
		//收到的数据组不了业务包，则返回null以告诉框架数据不够
		if(readableLength < HelloPacket.HEADER_LENGTH){
			return null;
		}
		
		//读取消息体的长度
		int bodyLength = buffer.getInt();
		
		//数据不正确，则抛出AioDecodeException异常
		if(bodyLength < 0){
			throw new AioDecodeException("bodyLength [" + bodyLength + "] is not right,remote:" + channelContext.getClientNode());
		}
		
		//计算本次需要的数据长度
		int neededLength = HelloPacket.HEADER_LENGTH + bodyLength;
		//判断收到的数据是否足够组包
		int isDataEnough = readableLength - neededLength;
		
		if(isDataEnough < 0){ //不够消息体长度(剩下的buffer组不了消息体)
			return null;
		}else{ //组包成功
			HelloPacket imPacket = new HelloPacket();
			if(bodyLength > 0){
				byte[] dst = new byte[bodyLength];
				buffer.get(dst); //get():此方法将字节从此缓冲区传输到给定的目标数组。
				imPacket.setBody(dst);
			}
			return imPacket;
		}
	}
	
	
}
